# This class is responsible sorting family members.
# Sorting is necessary when table is drawn, and the colums should be sorted according to affection status\type.
package FamilyOrganaizer;
use strict;
use PedWrapper;

# Affection status is described here: "http://bioinfo.cs.technion.ac.il/superlink/Pedigree_File.html"
our $UNKNOWN_STATUS = "0";
our $UN_AFFECTED_STATUS = "1";
our $AFFECTED_STATUS = "2";

# Constructor
# Input: pedWrapper (for reading family data), and current family number
sub new ( $ )
{
	my ($class, $pedWrapper, $familyNumber) = @_;
    my $self = {
		_pedWrapper   => $pedWrapper,
		_familyNumber   => $familyNumber,
		_sortedMembersByTypes => [],
		_sortedMembers => [],
		_lastTyped => [],
		_lastAffected => [],
		_translatedLabels => [],
	};
    bless $self, $class;
	$self->sortPeopleByAffectionAndType();
	$self->_sortAllFamilyMemebrs();
    return $self;
}

# Sort people to groups according to their data from the pedFile
# Input: pedWrapper (for reading family data), and current family number
sub sortPeopleByAffectionAndType {
	my ($self) = @_;
	my $pedWrapper = $self->{_pedWrapper};
	my $familyNumber = $self->{_familyNumber};
	
	# all posible groups are initialized to empty arrays
	my $sortedMembers = {};
	$sortedMembers->{$AFFECTED_STATUS}{"true"}=();
	$sortedMembers->{$UN_AFFECTED_STATUS}{"true"}=();
	$sortedMembers->{$UNKNOWN_STATUS}{"true"}=();
	$sortedMembers->{$AFFECTED_STATUS}{"false"}=();
	$sortedMembers->{$UN_AFFECTED_STATUS}{"false"}=();
	$sortedMembers->{$UNKNOWN_STATUS}{"false"}=();
		
	# insert each person to it's group
	for my $personNum ( $pedWrapper->getFamilyMembers($familyNumber)) {
		my $personData = $pedWrapper->{FAMILIES}{$familyNumber}{$personNum};
		push(@{$sortedMembers->{$personData->affectionStatus()}{$personData->isTyped()}} , $personNum);
	}
	$self->{_sortedMembersByTypes} =  $sortedMembers;
}
# Get number of people in a specific group
# Input: 	affectionStatus- only members with this affection status will be counted
# 			isTyped- 	possible parameter. If this parameter is supllied- only people with "affectionStatus" and "isTyped" will be counted.
#						If this parameter isn't supllied- people with "affectionStatus", both "typed" and "unTyped" will be counted.
sub getNumberOfAffected {
	my ($self,  $affectionStatus, $isTyped) = @_;
	
	if (defined $isTyped){
		my $size = $#{$self->{_sortedMembersByTypes}->{$affectionStatus}{$isTyped}} + 1;
		return $size;	
	}
	else{
		my $size1 = $#{$self->{_sortedMembersByTypes}->{$affectionStatus}{"true"}} + 1;
		my $size2 = $#{$self->{_sortedMembersByTypes}->{$affectionStatus}{"false"}} + 1;
		return $size1 + $size2;	
	}
}

# Get all family members, sorted.
# First will come Affected members: typed, then unTyped.
# After will come UnAffected members: typed, then unTyped.
# After will come Unknown members: typed, then unTyped.
sub getSortedFamilyMembers{
	my ($self) = @_;
	return @{$self->{_sortedMembers}};
}

# Sort all family members, and plave them in the array '$self->{_sortedMembers}'.
# First will come Affected members: typed, then unTyped.
# After will come UnAffected members: typed, then unTyped.
# After will come Unknown members: typed, then unTyped.
sub _sortAllFamilyMemebrs {
	my ($self) = @_;
	my $sortedMembers = $self->{_sortedMembersByTypes};
	
	my @members = ();
	my @lastAffected = ();
	my @lastTyped = ();
	my $lastAffected = "";
	my $lastTyped = "";
	for my $personNum (@{$sortedMembers->{$AFFECTED_STATUS}{"true"}}) {
		push(@members, $personNum);
		$lastTyped = $personNum;
		$lastAffected = $personNum;
	}
	push(@lastTyped, $lastTyped);
	for my $personNum (@{$sortedMembers->{$AFFECTED_STATUS}{"false"}}) {
		push(@members, $personNum);
		$lastTyped = $personNum;
		$lastAffected = $personNum;
	}
	push(@lastTyped, $lastTyped);
	push(@lastAffected, $lastTyped);
	for my $personNum (@{$sortedMembers->{$UN_AFFECTED_STATUS}{"true"}}) {
		push(@members, $personNum);
		$lastTyped = $personNum;
		$lastAffected = $personNum;
	}
	push(@lastTyped, $lastTyped);
	for my $personNum (@{$sortedMembers->{$UN_AFFECTED_STATUS}{"false"}}) {
		push(@members, $personNum);
		$lastTyped = $personNum;
		$lastAffected = $personNum;
	}
	push(@lastTyped, $lastTyped);
	push(@lastAffected, $lastTyped);
	for my $personNum (@{$sortedMembers->{$UNKNOWN_STATUS}{"true"}}) {
		push(@members, $personNum);
		$lastTyped = $personNum;
		$lastAffected = $personNum;
	}
	push(@lastTyped, $lastTyped);
	for my $personNum (@{$sortedMembers->{$UNKNOWN_STATUS}{"false"}}) {
		push(@members, $personNum);
		$lastTyped = $personNum;
		$lastAffected = $personNum;
	}
	push(@lastTyped, $lastTyped);
	push(@lastAffected, $lastTyped);
	$self->{_lastTyped} = \@lastTyped;
	$self->{_lastAffected} = \@lastAffected;
	$self->{_sortedMembers} = \@members;
}

# Return true if a person in the last person in an affection status
# (This is used for drawing different borders)
# Input: person number
sub isLastAffected {
	my ($self, $personNum) = @_;
	my @lastAffected = @{$self->{_lastAffected}};
	for my $lastAffectedPrson (@lastAffected) { 
		(not ($personNum eq $lastAffectedPrson)) || return "true";
	}
	return "false";
}

# Return true if a person in the last person in an typed status
# (This is used for drawing different borders)
# Input: person number
sub isLastTyped {
	my ($self, $personNum) = @_;
	my @lastTyped = @{$self->{_lastTyped}};
	for my $lastTypedPerson (@lastTyped) { 
		(not ($personNum eq $lastTypedPerson)) || return "true";
	}
	return "false";
}

sub translateLabels{
	my ($self, $parser, $firstMarkerName) = @_;
	my $pedWrapper = $self->{_pedWrapper};
	my $familyNumber = $self->{_familyNumber};
	
	my $translatedLabels = {};
	my $counter = 1;
	
	for my $personNum ($self->getSortedFamilyMembers){
		my $labelCellData = $parser->getLabelCell($personNum, $firstMarkerName); 
		#if person is a founder
		if ($pedWrapper->getParent($familyNumber, $personNum, "0") eq "0"){
			my $currentLabel = $labelCellData->val1();
			$translatedLabels->{$currentLabel} = "$counter";
			$counter += 1;
		}
		if ($pedWrapper->getParent($familyNumber, $personNum, "1") eq "0"){
			my $currentLabel = $labelCellData->val2();
			$translatedLabels->{$currentLabel} = "$counter";
			$counter += 1;
		}
	}
	$self->{_translatedLabels} = $translatedLabels;
}

sub getTranslatedLabel(){
	my ($self, $label) = @_;
	if ($label eq "0"){
		return "0";
	}
	defined $self->{_translatedLabels}->{$label} || die "error: there is no translation for label $label";
	return $self->{_translatedLabels}->{$label};
}

1;
